#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "w25q128.h"
#include "spi.h"
#include "bsp_log.h"

#define MODE_NAME "SPI"
#define SPI_LOG_INFO(fmt, ...) BSP_LOG(LOG_INFO,"%s %s-%d "fmt,MODE_NAME,__FUNCTION__,__LINE__, ##__VA_ARGS__)
#define SPI_LOG_DEBUG(fmt, ...) BSP_LOG(LOG_DEBUG, "%s %s-%d "fmt,MODE_NAME,__FUNCTION__, __LINE__,##__VA_ARGS__)
#define SPI_LOG_ERROR(fmt, ...) BSP_LOG(LOG_ERROR, "%s %s-%d "fmt,MODE_NAME,__FUNCTION__, __LINE__,##__VA_ARGS__)

//Flash CMD 命令
#define READ_ID_CM 0x9F
#define ENABLE_WRITE_CMD 0x06
#define ENABLE_READ_CME 0x03
#define WAITE_BUSY 0x05
#define CLEAR_ALL_CHIPE 0xC7
#define CLEAR_SCOKET 0x20

//外部串口输入命令
#define WRITE "Write"
#define READ "Read"
#define ID "Id"
#define CLEARALL "Clear"
#define SECTORERASE "SectorErase"


//当前flash地址记录，重启之后失效-必须执行Clear命令
uint32_t addr = 0x000000;
uint32_t cur_addr = 0;

/**
 * @brief  通过 SPI 发送和接收数据
 * @param  recv_data 接收缓冲区指针（如果不接收数据可传 NULL）
 * @param  send_data 发送缓冲区指针（如果不发送数据可传 NULL）
 * @param  send_len  发送字节数
 * @param  recv_len  接收字节数
 * @retval None
 */
static void W25Q_SPI_TransmitReceive(uint8_t *recv_data,uint8_t *send_data,uint16_t send_len,uint16_t recv_len)
{
    if(send_data) {
        HAL_SPI_Transmit(&hspi1, send_data, send_len, HAL_MAX_DELAY);
    }
    if(recv_data) {
        HAL_SPI_Receive(&hspi1, recv_data, recv_len, HAL_MAX_DELAY);
    }
}

/**
 * @brief  等待 W25Q 空闲
 * @note   轮询状态寄存器的 BUSY 位（bit0），直到为 0 表示空闲
 * @retval None
 */
static void W25Q_WaitBusy(void) {
    uint8_t cmd = WAITE_BUSY;
    uint8_t status;
    do {
        W25Q_CS_LOW();
        W25Q_SPI_TransmitReceive(&status,&cmd,1,1);
        W25Q_CS_HIGH();
    } while (status & 0x01);
}

/**
 * @brief  使能写入（WEL=1）
 * @note   必须在写入或擦除之前调用
 * @retval None
 */
void W25Q_WriteEnable(void)
{
    W25Q_CS_LOW();
    uint8_t cmd = ENABLE_WRITE_CMD;
    W25Q_SPI_TransmitReceive(NULL,&cmd,1,0);
    W25Q_CS_HIGH();
//    SPI_LOG_INFO("Write Enable Success\n");
}

/**
 * @brief  读取 Flash JEDEC ID
 * @note   返回值格式：Manufacturer ID + Memory Type + Capacity
 * @retval 24位 JEDEC ID
 */
uint32_t W25Q_ReadID(void)
{
    uint8_t cmd = READ_ID_CM;
    uint8_t id[3]={0};
    W25Q_CS_LOW();
    W25Q_SPI_TransmitReceive(id,&cmd,1,3);
    W25Q_CS_HIGH();
    SPI_LOG_INFO("CMD 0x9F Read Id Success: %02X%02X%02X\r\n",id[0], id[1], id[2]);
    return (id[0] << 16)| (id[1] << 8) | id[2];
}

uint32_t W25Q_ReadSimpID(void)
{
    uint8_t cmd[4] = {0x90, 0x00, 0x00, 0x00};  // 发送指令 + 3 字节 Dummy 地址
	uint8_t id[2];
    W25Q_CS_LOW();
    W25Q_SPI_TransmitReceive(id,cmd,4,2);
    W25Q_CS_HIGH();
    SPI_LOG_INFO("CMD 0x90 Read Id Success: %02X%02X\r\n",id[0], id[1]);
    return (id[0] << 8)| id[1] ;
}

/**
 * @brief  从 W25Q 读取数据
 * @param  addr 起始地址
 * @param  buf  数据存储缓冲区
 * @param  len  读取字节数
 * @retval None
 */
void W25Q_ReadData(uint32_t addr, uint8_t *buf, uint16_t len)
{
    uint8_t cmd[4];
    cmd[0] = ENABLE_READ_CME;
    cmd[1] = (addr >> 16) & 0xFF;
    cmd[2] = (addr >> 8) & 0xFF;
    cmd[3] = addr & 0xFF;
    W25Q_CS_LOW();
    W25Q_SPI_TransmitReceive(buf,cmd,4,len);
    W25Q_CS_HIGH();
    W25Q_WaitBusy();
//    SPI_LOG_INFO("Read Data Success data:%s\r\n",(char *)buf);
}

/**
 * @brief  页编程（Page Program）
 * @param  addr 写入起始地址（页内，1 页 = 256 字节）
 * @param  str  写入数据指针
 * @param  len  写入数据长度
 * @retval None
 */
void W25Q_PageProgram(uint32_t addr, char *str, uint16_t len)
{
    len = 4 + len;
    uint8_t buf[len];
    buf[0] = 0x02;
    buf[1] = (addr >> 16) & 0xFF;
    buf[2] = (addr >> 8) & 0xFF;
    buf[3] = addr & 0xFF;
    memcpy(&buf[4], str, len);

    W25Q_WriteEnable();
    W25Q_CS_LOW();
    W25Q_SPI_TransmitReceive(NULL, buf, len, 0);
    W25Q_CS_HIGH();
    W25Q_WaitBusy();
//    SPI_LOG_INFO("Write Data Success \r\n");
}

/**
 * @brief  整片擦除（Chip Erase）
 * @note   耗时 10~30 秒
 * @retval None
 */
void W25Q_ChipErase(void) {
    W25Q_WriteEnable();
    uint8_t cmd = CLEAR_ALL_CHIPE;
    W25Q_CS_LOW();
    SPI_LOG_INFO("Start Erase All Chip");
    W25Q_SPI_TransmitReceive(NULL,&cmd,1,0);
    W25Q_CS_HIGH();
    W25Q_WaitBusy();
    SPI_LOG_INFO("Erase All Chip Success\r\n");
    cur_addr = 0;
}

/**
 * @brief  擦除指定地址所在的 4KB 扇区
 * @param  addr 要擦除的地址
 * @retval None
 */
void W25Q_SectorErase(uint32_t addr) {
    W25Q_WriteEnable();
    uint8_t cmd[4];
    cmd[0] = CLEAR_SCOKET;
    cmd[1] = (addr >> 16) & 0xFF;
    cmd[2] = (addr >> 8) & 0xFF;
    cmd[3] = addr & 0xFF;
    SPI_LOG_INFO("Start Erase Addr:%x Chip",addr);
    W25Q_CS_LOW();
    HAL_SPI_Transmit(&hspi1, cmd, 4, HAL_MAX_DELAY);
    W25Q_CS_HIGH();
    W25Q_WaitBusy();
    SPI_LOG_INFO("Erase Addr:%x Chip Success",addr);
    cur_addr = 0;
}

/**
 * @brief  串口数据处理函数
 * @param  uart_data 串口接收到的数据
 * @param  len       数据长度
 * @retval None
 */
void uart_rx_data(uint8_t *uart_data,uint16_t len)
{
    if(!(strncmp((char *)uart_data,READ,strlen(READ))))
    {
        uint8_t buf[1024]={0};
        uint32_t read_len =  cur_addr - addr;
        if(read_len <= 0)
        {
            SPI_LOG_INFO("Flash No Data Read\r\n");
            return;
        }
        W25Q_ReadData(addr, buf,read_len);
    }

    if(!(strncmp((char *)uart_data,WRITE,strlen(WRITE))))
    {
        W25Q_PageProgram(cur_addr,(char *)&uart_data[strlen(WRITE)],len - strlen(WRITE));
        cur_addr += len - strlen(WRITE);
    }

    if(!(strncmp((char *)uart_data,ID,strlen(ID))))
    {
		W25Q_ReadSimpID();
        W25Q_ReadID();
    }

    if(!(strncmp((char *)uart_data,CLEARALL,strlen(CLEARALL))))
    {
        W25Q_ChipErase();
    }

    if(!(strncmp((char *)uart_data,SECTORERASE,strlen(SECTORERASE))))
    {
        uint32_t clear_addr = (uint32_t)(uart_data[strlen(SECTORERASE)] - '0');
        W25Q_SectorErase(clear_addr);
    }
}


